import { isNilOrEmpty, notNilEmpty } from 'qx-util';

/**
 * 把对象格式的导航参数转换成数组格式的导航参数
 * @author lxm
 * @date 2023-07-10 03:33:14
 * @export
 * @param {any} navParams
 * @return {*}  {IPSNavigateParam[]}
 */
export function convertObjectToNavParams(navParams: any): any[] {
  const result: any[] = [];
  const reg = /^%(.+)%$/;
  // eslint-disable-next-line guard-for-in
  for (const key in navParams) {
    let rawValue = true;
    let value = navParams[key];
    if (notNilEmpty(navParams[key]) && reg.test(navParams[key])) {
      rawValue = false;
      value = navParams[key].substring(1, navParams[key].length - 1);
    }
    result.push({
      key: key.toLowerCase(),
      rawValue,
      value,
    } as any);
  }

  return result;
}

/**
 * 转换导航数据(如导航上下文，导航视图参数)
 * - 把%xxx%,转换成origins元素里对应叫xxx的值
 * - 按顺序查找origins的元素，且只要有xxx的属性就算找到，不管值是否为空。
 * - navany里{a:%xxx%}，origins里找不到xxx则返回值里不存在a属性
 * - navany里非%xxx%形式的，都当成直接值原样返回，包括空值。
 *
 * @author lxm
 * @date 2022-08-22 11:08:18
 * @export
 * @param {any[]} navParams 导航参数
 * @param {...any[]} origins 转换数据来源集合
 */
export function convertNavData(
  navParams: any[] | any | undefined | null,
  ...origins: any[]
): any {
  // 如果导航参数不存在或者为空对象，返回{}
  if (!navParams || Object.keys(navParams).length === 0) {
    return {};
  }

  // 把对象形式的导航参数转换成any[]形式
  const navParamsArr: any[] = Array.isArray(navParams)
    ? navParams
    : convertObjectToNavParams(navParams as any);

  return convertNavDataByArray(navParamsArr, ...origins);
}

/**
 * 从origins每个元素里找到对应属性key的值
 * 如果都找不到抛异常。
 * @author lxm
 * @date 2023-09-13 11:38:43
 * @param {any[]} origins 来源数据集合
 * @param {string} key 属性标识
 * @return {*}  {{ find: boolean; value: unknown }} 返回find是否找到值，value为找到的值，可以是空值
 */
function getVal(
  origins: any[],
  key: string,
): { find: boolean; value: unknown } {
  // 找到origins里第一个有该属性的的项
  const findOrigin = origins.find(item => {
    if (isNilOrEmpty(item)) {
      return false;
    }
    return (
      // proxy数据判断是否能拿到值
      item[key!] ||
      // 上下文等判断是否有这个属性，如果有且值为空，则赋该空值
      Object.prototype.hasOwnProperty.call(item, key!)
    );
  });
  return { find: !!findOrigin, value: findOrigin?.[key] };
}

/**
 * 通过模型中的导航数组 转换导航数据(如导航上下文，导航视图参数)
 * - 把%xxx%,转换成origins元素里对应叫xxx的值
 * - 按顺序查找origins的元素，且只要有xxx的属性就算找到，不管值是否为空。
 * - navany里{a:%xxx%}，origins里找不到xxx则返回值里不存在a属性
 * - navany里非%xxx%形式的，都当成直接值原样返回，包括空值。
 *
 * @author lxm
 * @date 2022-08-22 11:08:18
 * @export
 * @param {any[]} navanys 导航参数
 * @param {...any[]} origins 转换数据来源集合
 */
export function convertNavDataByArray(
  navanys: any[],
  ...origins: any[]
): any {
  const regex = /\$\{[^}]*\}/g; // 匹配${xxx}格式字符串
  const result: any = {};
  for (const navany of navanys) {
    if (!navany.rawValue) {
      const matchArr = navany.value!.match(regex);
      if (matchArr !== null) {
        // 有${xxx}的找每一个xxx的值，替换原始字符串里的值，最后赋值处理过的字符串
        let valueStr = navany.value!;
        matchArr.forEach((key: any) => {
          // 没有${xxx}
          const { find, value } = getVal(origins, key.slice(2, -1));
          if (find) {
            valueStr = valueStr.replace(key, `${value}`);
          }
        });
        result[navany.key!.toLowerCase()] = valueStr;
      } else {
        // 没有${xxx}
        const { find, value } = getVal(origins, navany.value!);
        if (find) {
          result[navany.key!.toLowerCase()] = value;
        }
      }
    } else {
      // 直接值，空值时赋null
      result[navany.key!.toLowerCase()] = navany.value || null;
    }
  }
  return result;
}

/**
 * 根据导航参数把多条数据转换成单条数据，用；分隔
 * @author lxm
 * @date 2023-07-10 04:31:30
 * @export
 * @param {(IPSNavigateParam[] | any | undefined | null)} navParams
 * @param {any[]} dataArr
 * @return {*}  {any}
 */
export function formatMultany(
  navParams: any[] | any | undefined | null,
  dataArr: any[],
): any {
  const result: any = {};
  if (!navParams) {
    return result;
  }
  const naviArr: any[] = Array.isArray(navParams)
    ? navParams
    : convertObjectToNavParams(navParams as any);

  const data1 = dataArr[0];
  naviArr.forEach(naviParam => {
    const { rawValue, value } = naviParam;
    // 非直接且取值的属性是数据的属性时，把多条数据的值合并到一起，用；分隔
    if (
      !rawValue &&
      value &&
      Object.prototype.hasOwnProperty.call(data1, value)
    ) {
      result[value] = dataArr.map(item => item[value]).join(';');
    }
  });
  return result;
}
